import os
import json
import zlib
import base64
import string
import random
import traceback
import urllib.request, urllib.parse, urllib.error

always_rerender = True

tutor.qtype_inherit('pythoncode')

render_html = render_html_upload
defaults['csq_show_skeleton'] = False
defaults['csq_extra_tests'] = []

def prep(string):
    if isinstance(string, str):
        string = string.encode()
    return base64.b64encode(zlib.compress(string)).decode()

def handle_submission(submissions, **info):
    code = submissions[info['csq_name']]
    code = csm_tools.data_uri.DataURI(code[1]).data.decode()
    code = code.replace('\r\n', '\n')

    fileloc = os.path.join(*([info['cs_data_root'], 'courses'] + info['cs_path_info'] + ['_files']))
    out_base = {
        'files': [],
        'username': info['cs_username'],
        'timeout': info.get('csq_timeout', 2),
        'mainfile': 'test.py',
        'page': '_'.join(info['cs_path_info']),
        'question': info['csq_name'],
        'magic': ''.join(random.choice(string.ascii_letters) for i in range(20)),
    }

    # put the student's code in
    out_base['files'].append(['lab.py', prep(code)])

    with open(os.path.join(fileloc, 'test.py')) as f:
        labtest = f.read()

    labtest = labtest + '\n\nprint(%r, len(cases)-errors, errors)' % out_base['magic']

    out_base['files'].append(['test.py', prep(labtest)])

    # grab the other files and put them in the format we want
    for i in info.get('csq_files', []):
        realpath = os.path.join(fileloc, i)
        if os.path.isdir(realpath):
            # this is a directory; recursively add
            for d,_,files in os.walk(realpath):
                for f in files:
                    out_base['files'].append([os.path.join(d[len(fileloc)+1:], f), prep(open(os.path.join(d, f), 'rb').read())])
        elif os.path.isfile(realpath):
            out_base['files'].append([i, prep(open(realpath, 'rb').read())])

    # log the magic number so we have it

    msg = ('<div class="%s_response"><h2>Test Results:</h2>') % info['csq_name']
    count = 1
    icheck = info['csq_input_check'](code)
    if icheck is not None:
        return {'score': 0.0, 'msg': '<font color="red">Error: %s</font>' % icheck}

    # construct request to send to receiver
    data = urllib.parse.urlencode({'json': json.dumps(out_base)}).encode()
    req = urllib.request.Request(info['csq_receiver'], data)
    try:
        resp = urllib.request.urlopen(req, data).read()
        resp = json.loads(resp.decode())
        info['cs_debug'](resp)
    except:
        resp = {'ok': False, 'error': traceback.format_exc()} 

    name = info['csq_name']

    if resp['ok']:
        msg += '<div class="bs-callout bs-callout-default" id="cs_partialresults_%s"><span id="cs_partialresults_%s_message">Your code has been sent to the server for testing.  Watch here for updates.</span><br/><center><img src="https://sicp-s4.mit.edu/tutor/__STATIC__/6.009/images/loading.gif"/></div>' % (name, name)
    else:
        msg += '<div class="bs-callout bs-callout-danger" id="cs_partialresults_%s">Error sending your results to the server: %s.</div>' % (name, resp['error'])

    msg += r'''<script type="text/javascript">
var magic_%s = %r;
if (typeof ws_%s != 'undefined'){
    ws_%s.close();
    var ws_%s = undefined;
}

$('#%s_score_display').html('working...');

$('#%s_buttons button').prop("disabled", true);

var ws_%s = new WebSocket(%r);

ws_%s.onopen = function(){
    ws_%s.send(JSON.stringify({api_token: catsoop.api_token, magic: magic_%s, page: %r, question: %r}));
}

ws_%s.onmessage = function(event){
    var m = event.data;
    var j = JSON.parse(m);
    var thediv = $('#cs_partialresults_%s')
    var themessage = $('#cs_partialresults_%s_message');
    if (j.type == 'inqueue'){
        thediv[0].className = '';
        thediv.addClass('bs-callout');
        thediv.addClass('bs-callout-warning');
        themessage.html('Your code is queued to be run (position ' + j.result + ').');
        $('#%s_buttons button').prop("disabled", true);
    }else if (j.type == 'running'){
        thediv[0].className = '';
        thediv.addClass('bs-callout');
        thediv.addClass('bs-callout-info');
        themessage.html('Your code is running.');
        $('#%s_buttons button').prop("disabled", true);
    }else if (j.type == 'newresult'){
        console.log('HELLO');
        var res = JSON.parse(j.result);
        $('#%s_score_display').html(res.score + ' point' + (res.score==1 ? '' : 's'));
        $('#%s_message').html(res.response);
        ws_%s.close();
        $('#%s_buttons button').prop("disabled", false);
    }else{
        $('#%s_buttons button').prop("disabled", true);
    }
}
</script>''' % (name, out_base['magic'], name, name, name, name, name, name, info['csq_websocket'], name, name, name, '_'.join(info['cs_path_info']), name,
                name, name, name, name, name, name, name, name, name, name)

    msg += '</div>'

    msg = '\n<br/>%s' % msg
    return {'score': 0, 'msg': msg}
